﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.WindowsAzure.StorageClient;
using AzureGames.Data.Implementation.ServiceEntities;
using Microsoft.WindowsAzure;
using System.Diagnostics;

namespace AzureGames.Data.Implementation
{
    public class ResourceRepository : IResourceRepository
    {
        protected CloudBlobContainer blobContainer;
        protected TraceSource Trace = new TraceSource("AzureGames");

        public ResourceRepository()
        {
            InitialiseContainer();
        }

        public Model.Resource GetResource(Guid ResourceID)
        {
            var sw = Stopwatch.StartNew();
            Model.Resource response = null;

            try
            {
                var blob = blobContainer.GetBlockBlobReference(ResourceID.ToString());
                blob.FetchAttributes();

                if (blob.Metadata.HasKeys())
                {
                    response = new Model.Resource
                    {
                        ID = ResourceID,
                        Bytes = blob.DownloadByteArray(),
                        ContentType = blob.Metadata["ContentType"],
                        CreatedDate = DateTime.Parse(blob.Metadata["CreatedDate"]),
                        LastUpdatedDate = DateTime.Parse(blob.Metadata["LastUpdatedDate"]),
                        Name = blob.Metadata["Name"]
                    };
                }
            }
            catch (Exception ex)
            {
                Trace.TraceEvent(TraceEventType.Error, 1001,
                                "ResourceRepository.GetResource({0}) failed with:{1}\nInnerMessage:{2}\nStackTrace:{3}",
                                ResourceID,
                                ex.Message,
                                ex.InnerException == null ? "" : ex.InnerException.Message,
                                ex.StackTrace);

                throw ex;
            }
            finally
            {
                sw.Stop();
                Trace.TraceInformation("ResourceRepository.GetResource({0}) found {2} in {1} ticks.", ResourceID, sw.ElapsedTicks, response == null ? "null" : response.Name);
            }

            return response;
        }

        /// <summary>
        /// this will both create and update a resource
        /// </summary>
        /// <param name="resource"></param>
        public void UpdateResource(Model.Resource resource)
        {
            var sw = Stopwatch.StartNew();

            try
            {
                var blob = blobContainer.GetBlockBlobReference(resource.ID.ToString());
                blob.UploadByteArray(resource.Bytes);

                blob.Metadata["ContentType"] = resource.ContentType;
                blob.Metadata["CreatedDate"] = resource.CreatedDate.ToString("u");
                blob.Metadata["LastUpdatedDate"] = DateTime.Now.ToString("u");
                blob.Metadata["Name"] = resource.Name;
                blob.SetMetadata();
                
            }
            catch (Exception ex)
            {
                Trace.TraceEvent(TraceEventType.Error, 1002,
                                "ResourceRepository.UpdateResource({0}) failed with:{1}\nInnerMessage:{2}\nStackTrace:{3}",
                                resource.ID,
                                ex.Message,
                                ex.InnerException == null ? "" : ex.InnerException.Message,
                                ex.StackTrace);

                //throw ex;
            }
            finally
            {
                sw.Stop();
                Trace.TraceInformation("ResourceRepository.UpdateResource({0}) completed in {1} ticks.", resource.ID, sw.ElapsedTicks);
            }      
       }

        public bool DeleteResource(Guid resourceID)
        {
            var sw = Stopwatch.StartNew();

            try
            {
                var blob = blobContainer.GetBlobReference(resourceID.ToString());
                return blob.DeleteIfExists();
            }
            catch (Exception ex)
            {
                Trace.TraceEvent(TraceEventType.Error, 1003,
                                "ResourceRepository.DeleteResource({0}) failed with:{1}\nInnerMessage:{2}\nStackTrace:{3}",
                                resourceID,
                                ex.Message,
                                ex.InnerException == null ? "" : ex.InnerException.Message,
                                ex.StackTrace);

                throw ex;
            }
            finally
            {
                sw.Stop();
                Trace.TraceInformation("ResourceRepository.DeleteResource({0}) completed in {1} ticks.", resourceID, sw.ElapsedTicks);
            } 
        }


        private void InitialiseContainer()
        {
            var account = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");
            var client = account.CreateCloudBlobClient();            
            blobContainer = client.GetContainerReference("resources");
            var created = blobContainer.CreateIfNotExist();
            Trace.TraceInformation("Initialised Resource Repository");
        }
    }
}
